﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ads
{
    public class Msg
    {
        public Packet packet = null;     
        public void fromByteArray(byte[] payload)
        {
            packet = new Packet(payload.Length);
            packet.fromByteArray(payload);
        }
        public void add(int type, byte[] payload)
        {
            packet = new Packet(payload.Length + PacketInfo.MAX_LENGTH);
            packet.info = new PacketInfo();
            packet.info.size = payload.Length;
            packet.info.type = type;
            Buffer.BlockCopy(payload, 0, packet.data, PacketInfo.MAX_LENGTH, payload.Length);
        }    
        public class Packet
        {
            public PacketInfo info = null;
            public byte[] data = null;
            public Packet(int size)
            {
                data = new byte[size];
            }

            public byte[] toByteArray()
            {
                byte[] header = info.toByteArray();
                Buffer.BlockCopy(header, 0, data, 0, header.Length);
                return data;
            }

            public void fromByteArray(byte[] buffer)
            {
                info = new PacketInfo();

                byte[] header = new byte[PacketInfo.MAX_LENGTH];
                Buffer.BlockCopy(buffer, 0, header, 0, header.Length);
                info.fromByteArray(header);

                if (info.size <= buffer.Length)
                {
                    data = new byte[info.size];
                    Buffer.BlockCopy(buffer, header.Length, data, 0, info.size);
                }
            }
        }

        public class PacketInfo
        {
            public const int MAX_LENGTH = 12;
            public const int MAGIC = 0x20140106;
            public int magic = 0x20140106;
            public int size = 0;
            public int type = 0;

            public byte[] toByteArray()
            {
                byte[] bMagic = new byte[4];
                byte[] bSize = new byte[4];
                byte[] bType = new byte[4];
                bMagic = htonl(magic, bMagic);
                bSize = htonl(size, bSize);
                bType = htonl(type, bType);

                byte[] ret = new byte[bMagic.Length + bSize.Length + bType.Length];
                Buffer.BlockCopy(bMagic, 0, ret, 0, bMagic.Length);
                Buffer.BlockCopy(bSize, 0, ret, bMagic.Length, bSize.Length);
                Buffer.BlockCopy(bType, 0, ret, bMagic.Length + bSize.Length, bType.Length);
                return ret;
            }

            public void fromByteArray(byte[] buffer)
            {
                byte[] bMagic = new byte[4];
                byte[] bSize = new byte[4];
                byte[] bType = new byte[4];

                Buffer.BlockCopy(buffer, 0, bMagic, 0, bMagic.Length);
                Buffer.BlockCopy(buffer, bMagic.Length, bSize, 0, bSize.Length);
                Buffer.BlockCopy(buffer, bMagic.Length + bSize.Length, bType, 0, bType.Length);

                magic = ntohl(bMagic);
                size = ntohl(bSize);
                type = ntohl(bType);
            }
        }

        public static int ntohl(byte[] buf)
        {
            byte[] buff = new byte[4];
            Array.Clear(buff, 0, buff.Length);
            Array.Copy(buf, 0, buff, 0, buff.Length);
            if (BitConverter.IsLittleEndian) Array.Reverse(buff);
            int ret = (Int32)BitConverter.ToInt32(buff, 0);
            return ret;
        }

        public static short ntohs(byte[] buf)
        {
            byte[] buff = new byte[2];
            Array.Clear(buff, 0, buff.Length);
            Array.Copy(buf, 0, buff, 0, buff.Length);
            if (BitConverter.IsLittleEndian) Array.Reverse(buff);
            short ret = (Int16)BitConverter.ToInt16(buff, 0);
            return ret;
        }

        public static byte[] htonl(int val, byte[] buf)
        {
            byte[] buff = BitConverter.GetBytes(val);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(buff);
            Buffer.BlockCopy(buff, 0, buf, 0, buff.Length);
            return buf;
        }

        public static byte[] htons(short val, byte[] buf)
        {
            byte[] buff = BitConverter.GetBytes(val);
            if (BitConverter.IsLittleEndian)
                Array.Reverse(buff);
            Buffer.BlockCopy(buff, 0, buf, 0, buff.Length);
            return buf;
        }

    }
}
